#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
// 自己的库
#include "HashTable.h"
#include "common.h"

#include "config.h"
#include "cmark-gfm.h"
#include "node.h"
#include "cmark-gfm-extension_api.h"
#include "syntax_extension.h"
#include "parser.h"
#include "registry.h"

#include "../extensions/cmark-gfm-core-extensions.h"


#define BUF_SIZE 4096

int is_char_whitespace(char ch){
	if ( ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r' ){
		return 1;
	}
	return 0;
}


void save_document(cmark_node *document,
				   int options, cmark_parser *parser, FILE* fp) {
	char *result;
	cmark_mem *mem = cmark_get_default_mem_allocator();
	result = cmark_render_html_with_mem(document, options, parser->syntax_extensions, mem);
	fprintf(fp, "%s", result);
	mem->free(result);
}


void parse_markdown(FILE* md_file, FILE* output_file){
	char buf[BUF_SIZE];
	cmark_parser *parser = NULL;
	size_t bytes;
	cmark_node *document = NULL;

	int options = CMARK_OPT_DEFAULT;
	options |= CMARK_OPT_HARDBREAKS;
	options |= CMARK_OPT_FOOTNOTES;
	options |= CMARK_OPT_VALIDATE_UTF8;
	options |= CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE;
	cmark_gfm_core_extensions_ensure_registered();
	parser = cmark_parser_new_with_mem(options, cmark_get_arena_mem_allocator());
	cmark_syntax_extension *syntax_extension_table = cmark_find_syntax_extension("table");
	cmark_syntax_extension *syntax_extension_strikethrough = cmark_find_syntax_extension("strikethrough");

	cmark_parser_attach_syntax_extension(parser, syntax_extension_table);
	cmark_parser_attach_syntax_extension(parser, syntax_extension_strikethrough);

	while ((bytes = fread(buf, 1, sizeof(buf), md_file)) > 0) {
		cmark_parser_feed(parser, buf, bytes);
		if (bytes < sizeof(buf)) {
			break;
		}
	}
	document = cmark_parser_finish(parser);

	save_document(document, options, parser, output_file);

	cmark_arena_reset();
	cmark_release_plugins();
}



int main(int argc, char *argv[])
{

	int res = 1;
	int template_file_index = 0;
	int output_file_index = 0;
	FILE* template_file = NULL;
	FILE* output_file = NULL;
	HashTable *template_args_table = HashTable_new(4);
	char *tmp_key;
	char *tmp_value;

// ---- 命令行参数 --------------------------------------------------------------

	for (int i = 1; i < argc; i++) {
		if ( (strcmp(argv[i], "-o") == 0) ){
			if ( output_file_index ){
				error("Too many output file for option '%s'\n", argv[i]);
				goto failure;
			}
			output_file_index = ++i;
		} else if( ( strcmp(argv[i], "-p") == 0 )){
			i++;
		    // 使用 strtok 函数将字符串分割成多个子字符串
		    tmp_key = strtok(argv[i], "=");

		    // 再次使用 strtok 函数分割剩余的字符串
		    tmp_value = strtok(NULL, "=");
		    if( tmp_value == NULL){
				HashTable_insert(template_args_table, tmp_key, "");
		    }else{
				HashTable_insert(template_args_table, tmp_key, tmp_value);
		    }
		} else { // treat as file argument
			if ( template_file_index != 0 ){
				error("Too many template file: '%s'\n", argv[i]);
				// error("Too many template file\n");
				goto failure;
			}
			template_file_index = i;
		}
	}

// ---- 模板文件和输出文件 ------------------------------------------------------

	if (template_file_index == 0){
		error("No template file provided.\n");
		goto failure;
	}
	template_file = fopen(argv[template_file_index], "r");

	if ( !template_file ){
		error("opening '%s' failed. \n", argv[template_file_index]);
		perror("");
		goto failure;
	}

	if ( output_file_index == 0){
		output_file = stdout;
	}else{
		output_file = fopen(argv[output_file_index], "w");
	}

	if ( !output_file ){
		error("opening '%s' failed. \n", argv[output_file_index]);
		perror("");
		goto failure;
	}


// ---- 解析模板参数 -----------------------------------------------------------

	int state = 0;
	int ch;

	char buf[BUF_SIZE] = "";

	char* pc_template_param;
	char* pc_template_param_end;
	char* pc_work = buf;

	char* template_arg;  // 存储匹配到的模板参数的值
	char* template_param_type;
	char* template_param_name;

	size_t bytes_read, bytes_written;
	FILE *tmp_file = NULL;
	// enum TemplateArgType type = TYPE_STR;

	while( (ch = fgetc(template_file)) != EOF ){
		switch(state){
		case 0:
			if ( ch == '{' ){
				state = 1;
			}
			break;
		case 1:
			if ( ch == '{' ){
				state = 2;
			}else{
				state = 0;
			}
			break;
		case 2:
			if ( is_char_whitespace(ch) ) state = 2;
			else {
				pc_template_param = pc_work;
				state=3;
			}
			break;
		case 3:
			if (is_char_whitespace(ch)){
				pc_template_param_end = pc_work;
				state = 4;
			}else if ( ch == '}'){
				pc_template_param_end = pc_work;
				state = 5;
			}else{
				state = 3;
			}
			break;
		case 4:
			if (is_char_whitespace(ch)){
				state = 4;
			}else if ( ch == '}' ){
				state = 5;
			}else {
				state = 0;
			}
			break;
		case 5:
			if ( ch == '}'){
				state = 6;
			}else{
				state = 0;
			}
			break;
		case 6:

		// ---- 模板解析：接受模板参数

			*pc_template_param_end = '\0';
			pc_work = buf;
			
			template_param_type = strtok(pc_template_param, ":");  // 这个是模板参数的参数类型
			template_param_name = strtok(NULL, ":");  // 模板参数的参数值
			if( template_param_name == NULL){
				// 找不到模板参数的参数类型，就默认为str类型，并且把整个模板参数当作模板参数的名字
				template_param_name = template_param_type;
			}
			template_arg = HashTable_search(template_args_table, template_param_name);

			if( template_arg == NULL){
				fflush(stdout);
				error("could NOT found the value of the template param '%s'\n", template_param_name);
				goto failure;
			}

		// ---- 填充带有模板参数的位置 ------------------------------------------------------------------

			// ---- file类型参数 --------------------------------------------------------

			if( !strcmp(template_param_type, "file") ){
				tmp_file = fopen( template_arg, "r");
				if ( tmp_file == NULL ){
					error("opening '%s' failed.\n", tmp_file);
					perror("");
					goto failure;
				}
				// 读取源文件并写入目标文件
				while ((bytes_read = fread(buf, 1, BUF_SIZE, tmp_file)) > 0) {
				    bytes_written = fwrite(buf, 1, bytes_read, output_file);
				    if (bytes_written != bytes_read) {
				        error("Error writing '%s' to '%s'", tmp_file, output_file);
				        goto failure;
				    }
				}
				fclose(tmp_file);
				tmp_file = NULL;

			// ---- file类型参数 --------------------------------------------------------

			}else if (!strcmp(template_param_type, "md")){
				tmp_file = fopen( template_arg, "r");
				if ( tmp_file == NULL ){
					error("opening '%s' failed.\n", tmp_file);
					perror("");
					goto failure;
				}
				parse_markdown(tmp_file, output_file);
				fclose(tmp_file);
				tmp_file = NULL;

			// ---- 默认类型参数（str类型） -----------------------------------------------

			}else{
				fputs(template_arg, output_file);
			}

			state = 0;
			break;
		default:
			error("Unkown parse state. \n");
			goto failure;
		}

		if( state == 0){
			if (pc_work != buf){
				*pc_work++ = ch;
				*pc_work = '\0';
				pc_work = buf;
				fputs(buf, output_file);
				continue;
			}
			fputc(ch, output_file);
			continue;
		}
		*pc_work++ = ch;
	}

	success:
	  res = 0;

	failure:

	return res;
}


